// Copyright 2023 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef STREAMPARSE_H
#define STREAMPARSE_H

#include <array>
#include <mutex>
#include <thread>

#include "Communication/InterThreadComm.h"
#include "Communication/Socket/VmiSocket.h"
#include "Include/msghead.h"

class ServiceHandle {
public:
    /**
     * @brief: interface
     * @param [in] pPkt: packet
     */
    virtual void Handle(const VmiBuffer& pPkt) = 0;
    virtual ~ServiceHandle() {}
    /**
     * @brief: interface
     * @return: packet
     */
    virtual uint8_t* GetNextPkt() { return nullptr; }
     /**
     * @brief: interface
     * @param [in] packet: compelete message
     * @return: return reassemble message
     */
    virtual uint8_t* Reassemble(const VmiBuffer& packet) { return packet.GetPointer(); }

};

class StreamParse {
public:
    StreamParse();
    ~StreamParse();

    /**
     * @brief: set handle with type
     * @param [in] type: type
     * @param [in] serviceHandle: handle
     */
    void SetServiceHandle(unsigned char type, std::shared_ptr<ServiceHandle> serviceHandle);

    /**
     * @brief: get handle with type
     * @param [in] type: type
     * @param [in] serviceHandle: handle
     */
    ServiceHandle* GetServiceHandle(unsigned char type);

    /**
     * @brief: parse socket stream
     * @param: [in] packetDataBuf: packetDataBuf
     * @param: [in] bufLen: bufLen
     * @param: [in] packetData: packetData
     * @param: [out] packetDataLength: packetDataLength
     */
    uint8_t* ParseStream(uint8_t* packetDataBuf, int buflen, uint8_t* packetData, int& pdatalen);

private:

    /**
     * @brief: check packet
     * @param [in] packetData: packet
     * @param [in] len: data length
     * @return: packet length or error code
     */
    int PacketDelimiter(uint8_t* packetData, int len);

    /**
     * @brief: process packet
     * @param [in] packetData: data point
     * @param [out] packetLength: data length
     * @return: position of data
     */
    uint8_t* ProcessMsg(uint8_t* packetData, int& dataLen, int packetLength);

    std::array<std::shared_ptr<ServiceHandle>, VMIMsgType::End> m_serviceHandle = {};
};

class StreamParseThread {
public:
    struct ThreadPara {
        std::shared_ptr<VmiSocket> m_vmiSocket = nullptr;
        StreamParse* m_streamParse = nullptr;
        volatile int m_threadStatus = -1;

        /**
         * @brief: process recv message
         * @param [in] recvBuf: recv buff
         * @param [in] streamParse: streamParse
         * @param [out] dataLen：buff length
         */
        void ProcessRecvMsg(uint8_t* recvBuf, StreamParse& streamParse, int& dataLen);
    };

    /**
     * @brief: constructor
     * @param [in] vmiSocket: socket
     */
    explicit StreamParseThread(std::shared_ptr<VmiSocket> vmiSocket);

    ~StreamParseThread();

    /**
     * @brief: start thread
     */
    int Start();

    /**
     * @brief: stop thread
     */
    int Stop();

    /**
     * @brief: set m_streamParse
     */
    void SetStreamParse(StreamParse* streamParse);
private:
    std::mutex m_lock = {};
    std::shared_ptr<VmiSocket> m_vmiSocket = nullptr;
    std::shared_ptr<ThreadPara> m_threadParameter = nullptr;
    std::thread* m_task = nullptr;
    StreamParse* m_streamParse = nullptr;
    /**
     * @brief: thread process
     * @param [in] streamParseThreadObj: thread parameter
     */
    friend void Taskentry(std::shared_ptr<StreamParseThread::ThreadPara> streamParseThreadObj);
};

#endif
